#include "system.h"
#include "print.h"

//0x4000~0x5000
#ifdef ISBIOS
#define POS 0x4000
#define defaultStream ( *( (struct Stream**)(BIOSRAM + POS + 0x00) ) )
#else
struct Stream* defaultStream;
#endif


void setDefaultStream(struct Stream* s){
  defaultStream = s;
}

void putc(int val){
  defaultStream->putc(defaultStream, val);
}
int getc(){
  return defaultStream->getc(defaultStream);
}
//int print(const char* str){
//  int idx = 0;
//  while(1){
//    char tmp = str[idx];
//    if(tmp=='\0')break;
//    defaultStream->putc(defaultStream, tmp);
//    idx++;
//  }
//}

/*
int printLen(const char* str, int len){
  int idx = 0;
  int i;
  for(i=0;i<len;i++){
    char tmp = str[i];
    putc(tmp);
  }
}
*/

void print(const char* str){
  sprint(defaultStream, str);
}
void sprint(struct Stream* stream, const char* str){
  int idx = 0;
  while(1){
    int tmp1 = str[idx]&0xFF;
    int tmp2 = str[idx+1]&0xFF;
    if(tmp1=='\0')break;
    if(tmp1>=0xA0 && tmp2>=0xA0){
      stream->putcgb(stream, tmp1, tmp2);
      idx+=2;
    }else{
      stream->putc(stream, tmp1);
      idx++;
    }
  }
}

void printByte(int val){
  sprintByte(defaultStream, val);
}
void sprintByte(struct Stream* s, int val){
  char* chardata = "0123456789ABCDEF";
  s->putc(s, chardata[(val>>4)&0x0F]);
  s->putc(s, chardata[(val)&0x0F]);
}

void printHex(int val){
  sprintHex(defaultStream, val);
}
void sprintHex(struct Stream* s, int val){
  char* chardata = "0123456789ABCDEF";
  s->putc(s, chardata[(val>>28)&0x0F]);
  s->putc(s, chardata[(val>>24)&0x0F]);
  s->putc(s, chardata[(val>>20)&0x0F]);
  s->putc(s, chardata[(val>>16)&0x0F]);
  s->putc(s, chardata[(val>>12)&0x0F]);
  s->putc(s, chardata[(val>>8)&0x0F]);
  s->putc(s, chardata[(val>>4)&0x0F]);
  s->putc(s, chardata[(val)&0x0F]);
}

int printBin(int data2){
  int i;
  for(i=31;i>=0;i--){
    putc((data2>>i)&1?'1':'0'); // Status Byte
  }
}


int equal(const char* a,const  char* b, int maxlen){
  int i = 0;
  while(1){
    if(a[i]!=b[i]){
      return 0;
    }
    if(a[i]=='\0' && b[i]=='\0'){
      break;
    }
    if(a[i]=='\0' || b[i]=='\0'){
      return 0;
    }
    
    i++;
    if(maxlen>0){
      if(i>=maxlen){
        break;
      }
    }
  }
  return 1;
}

int scan(char* buff, int maxlen){
  int idx = 0;
  while(1){
    int c = getc();
    if(c==-1){
      return 0;
    }
    if(maxlen>=0){
      if(idx>=maxlen){
        buff[idx] = (char)0;
        return idx;
      }
    }
    if(c==0x0A){
      buff[idx] = 0;
      return idx;
    }else if(c==0x08){
      if(idx>0){
        idx--;
      }
    }else{
      buff[idx] = (char)c;
      idx++;
    }
  }
  
}

const int num10s[] = {
1000000000,
100000000,
10000000,
1000000,
100000,
10000,
1000,
100,
10,
1,
};

int toBcd(int val)
{
  int idx;
  int i;
  int num;
  if(val>=0){
    num = val;
  }else{
    return 0;
  }
  
  int bcd = 0;
  int outNum;
  int flg = 0;
  for(idx = 2; idx < 10 ; idx++)
  {
    outNum = 0;
    int CmpNum = num10s[idx];
    for(i = 0; i < 10 ; i++)
    {
      if(num>=CmpNum)
      {
        num -= CmpNum;
        outNum++;
      }
      else
      {
        break;
      }
    }
    bcd|=outNum<<((32-(idx-1))<<2);
  }
  return bcd;
}

void printInt(int val){
  sprintInt(defaultStream, val);
}
void sprintInt(struct Stream* stream, int val){
  int idx;
  int i;
  int num;
  if(val>=0){
    num = val;
    stream->putc(stream, '+');
  }else{
    num = -val;
    stream->putc(stream, '-');
  }
  
  stream->putc(stream, '0');
  int outNum;
  int flg = 0;
  for(idx = 0; idx < 10 ; idx++)
  {
    outNum = 0;
    int CmpNum = num10s[idx];
    for(i = 0; i < 10 ; i++)
    {
      if(num>=CmpNum)
      {
        num -= CmpNum;
        outNum++;
      }
      else
      {
        break;
      }
    }
    if(flg==1){
      stream->putc(stream, '0' + outNum);
    }else{
      if(outNum!=0){
        stream->putc(stream, '0' + outNum);
        flg = 1;
      }
    }
  }
}

int scanInt(){
  char buff[10];
  int i;
  int j;
  int idx = 0;
  int neg = 0;
  char v;
  while(1){
    v = getc();
    if(v=='-'||(v>='0'&&v<='9')){
      break;
    }
  }
  for(i = 0; i < 10 ; i++)
  {
    if(i==0 && v=='-'){
      neg = 1;
    }else{
      if(v<'0'||v>'9'){
        break;
      }
      buff[idx++] = v;
    }
    v = getc();
  }
  
  int val = 0;
  
  for(i = 0; i < idx ; i++)
  {
    for(j = 0; j < (int)(buff[i]-'0') ; j++)
    {
      val+=num10s[10-idx+i];
    }
  }
  if(neg){
    val=-val;
  }
  return val;
}

int scanByte(){
  int v1 = getc();
  int v2 = getc();
  int val = 0;
  
  if(v1>='0' && v1<='9'){
    val|=v1-'0';
  }else if(v1>='A' && v1<='F'){
    val|=v1-'A'+10;
  }else if(v1>='a' && v1<='f'){
    val|=v1-'a'+10;
  }
  val <<= 4;
  if(v2>='0' && v2<='9'){
    val|=v2-'0';
  }else if(v2>='A' && v2<='F'){
    val|=v2-'A'+10;
  }else if(v2>='a' && v2<='f'){
    val|=v2-'a'+10;
  }
  return val;
}

int getByte(char* chr){
  int v1 = chr[0];
  int v2 = chr[1];
  int val = 0;
  
  if(v1>='0' && v1<='9'){
    val|=v1-'0';
  }else if(v1>='A' && v1<='F'){
    val|=v1-'A'+10;
  }else if(v1>='a' && v1<='f'){
    val|=v1-'a'+10;
  }
  val <<= 4;
  if(v2>='0' && v2<='9'){
    val|=v2-'0';
  }else if(v2>='A' && v2<='F'){
    val|=v2-'A'+10;
  }else if(v2>='a' && v2<='f'){
    val|=v2-'a'+10;
  }
  return val;
}


#ifdef HAVE_MATH

const double num10d[] = {
1000000000000000.0,
100000000000000.0,
10000000000000.0,
1000000000000.0,
100000000000.0,
10000000000.0,
1000000000.0,
100000000.0,
10000000.0,
1000000.0,
100000.0,
10000.0,
1000.0,
100.0,
10.0,
1.0,
};
const double num10f[] = {
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001,
0.0000000000000001,
0.00000000000000001,
};

double scanDouble(){
  char buff[16];
  char buff2[16];
  int j;
  int idx = 0;
  int idx2 = 0;
  int neg = 0;
  char v;
  int i;
  for(i = 0; i < 16 ; i++)
  {
    v = getc();
    if(i==0 && v=='-'){
      neg = 1;
    }else{
      if(v<'0'||v>'9'){
        break;
      }
      buff[idx++] = v;
    }
  }
  
  if(v=='.'){
    for(i = 0; i < 16 ; i++)
    {
      v = getc();
      if(v<'0'||v>'9'){
        break;
      }
      buff2[idx2++] = v;
    }
  }
  
  double val = 0;
  for(i = 0; i < idx ; i++)
  {
    val+=num10d[16-idx+i]*((double)(int)(buff[i]-'0'));
  }

  for(i=0;i<idx2;i++){
    v = buff2[i];
    if(v<'0'||v>'9'){
      break;
    }
    val+=num10f[i]*((double)(int)(v-'0'));
  }

  
  if(neg){
    val=-val;
  }
  return val;
}

void printDouble(double v){
  sprintDouble(defaultStream, v);
}
void sprintDouble(struct Stream* s, double v){
  if(v<0){
    v=-v;
    s->putc(s, '-');
  }
  int lv = (int)v;
  char buff[16];
  int idx=0;
  if(lv!=0){
    while(1){
      int rem = lv % 10;
      buff[idx++] = '0'+rem;
      lv = lv / 10;
      if(lv==0)break;
    }
    while(idx>0){
      s->putc(s, buff[--idx]);
    }
  }else{
    s->putc(s, '0');
  }
  s->putc(s, '.');
  double v1 = v - (double)(int)v;
  int i;
  for(i=0;i<16;i++){
    v1 = v1 * 10;
    s->putc(s, '0'+(int)v1);
    v1 = v1 - (double)(int)v1;
  }
}
#endif
